// Decompiled by Jad v1.5.8e2. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://kpdus.tripod.com/jad.html
// Decompiler options: packimports(3) fieldsfirst ansi space 
// Source File Name:   CurvePlotter.java

package com.java4less.rchart;

import com.java4less.rchart.gc.ChartGraphics;
import com.java4less.rchart.gc.Polygon;

// Referenced classes of package com.java4less.rchart:
//			LinePlotter, RMatrix, LineDataSerie, LineStyle, 
//			FillStyle

public class CurvePlotter extends LinePlotter
{

	private static final int X = 0;
	private static final int Y = 1;
	public int segments;

	public CurvePlotter()
	{
		segments = 24;
	}

	private float b(int i, float t)
	{
		switch (i)
		{
		case -2: 
			return (((-t + 3F) * t - 3F) * t + 1.0F) / 6F;

		case -1: 
			return ((3F * t - 6F) * t * t + 4F) / 6F;

		case 0: // '\0'
			return (((-3F * t + 3F) * t + 3F) * t + 1.0F) / 6F;

		case 1: // '\001'
			return (t * t * t) / 6F;
		}
		return 0.0F;
	}

	private int[] p(int i, float t, int linePointsSC[][])
	{
		float px = 0.0F;
		float py = 0.0F;
		for (int j = -2; j <= 1; j++)
		{
			px += b(j, t) * (float)linePointsSC[0][i + j];
			py += b(j, t) * (float)linePointsSC[1][i + j];
		}

		int point[] = new int[2];
		point[0] = Math.round(px);
		point[1] = Math.round(py);
		return point;
	}

	private void plotLeastSquares(ChartGraphics g, int linePointsSC[][], LineDataSerie l)
	{
		int pts = linePointsSC[0].length;
		int degree = 1;
		RMatrix Pm = new RMatrix(pts, degree + 1);
		RMatrix Ym = new RMatrix(pts, 1);
		for (int i = 0; i < pts; i++)
		{
			for (int k = 0; k <= degree; k++)
				Pm.setValue(i, k, Math.pow(linePointsSC[0][i], k));

			Ym.setValue(i, 0, linePointsSC[1][i]);
		}

		RMatrix T = Pm.transpose();
		RMatrix MT = T.mult(Pm);
		RMatrix resultMatrix = MT.invert().mult(T).mult(Ym);
		double a1 = resultMatrix.getValue(0, 0);
		double a2 = resultMatrix.getValue(1, 0);
		int x1 = linePointsSC[0][0];
		int y1 = (int)Math.round(a1 + (double)x1 * a2);
		int x2 = linePointsSC[0][pts - 1];
		int y2 = (int)Math.round(a1 + (double)x2 * a2);
		l.style.draw(g, x1, y1, x2, y2);
	}

	private void plotBSPLines(ChartGraphics g, int plinePointsSC[][], LineDataSerie l)
	{
		int linePointsSC[][] = new int[2][plinePointsSC[0].length + 2];
		for (int i = 0; i < plinePointsSC[0].length; i++)
		{
			linePointsSC[0][i + 1] = plinePointsSC[0][i];
			linePointsSC[1][i + 1] = plinePointsSC[1][i];
		}

		linePointsSC[0][0] = linePointsSC[0][1];
		linePointsSC[1][0] = linePointsSC[1][1];
		linePointsSC[0][linePointsSC[0].length - 1] = plinePointsSC[0][plinePointsSC[0].length - 1];
		linePointsSC[1][linePointsSC[0].length - 1] = plinePointsSC[1][plinePointsSC[0].length - 1];
		int pieces = segments;
		int xpoints[] = new int[pieces * (linePointsSC[0].length - 3) + 1 + 2];
		int ypoints[] = new int[pieces * (linePointsSC[0].length - 3) + 1 + 2];
		Polygon pol = new Polygon();
		int q[] = p(2, 0.0F, linePointsSC);
		xpoints[0] = q[0];
		ypoints[0] = q[1];
		int cou = 1;
		for (int i = 2; i < linePointsSC[0].length - 1; i++)
		{
			for (int j = 1; j <= pieces; j++)
			{
				q = p(i, (float)j / (float)pieces, linePointsSC);
				xpoints[cou] = q[0];
				ypoints[cou] = q[1];
				cou++;
			}

		}

		if (l.fillStyle != null)
		{
			xpoints[cou + 1] = xpoints[0];
			ypoints[cou + 1] = bottomCorners[1][0];
			xpoints[cou] = xpoints[cou - 1];
			ypoints[cou] = bottomCorners[1][1];
			l.fillStyle.drawPolygon(g, xpoints, ypoints, cou + 2);
		}
		xpoints[0] = linePointsSC[0][0];
		ypoints[0] = linePointsSC[1][0];
		xpoints[cou - 1] = linePointsSC[0][linePointsSC[0].length - 1];
		ypoints[cou - 1] = linePointsSC[1][linePointsSC[1].length - 1];
		l.style.drawOpenPolygon(g, xpoints, ypoints, cou);
	}

	private void plotCubicNatural(ChartGraphics g, int linePointsSC[][], LineDataSerie l)
	{
		float polyX[][] = naturalCubic(linePointsSC[0].length - 1, linePointsSC[0]);
		float polyY[][] = naturalCubic(linePointsSC[1].length - 1, linePointsSC[1]);
		int pieces = segments;
		int xpoints[] = new int[pieces * polyX[0].length + 1 + 2];
		int ypoints[] = new int[pieces * polyX[0].length + 1 + 2];
		xpoints[0] = Math.round(evalPolynomial(polyX[0][0], polyX[1][0], polyX[2][0], polyX[3][0], 0.0F));
		ypoints[0] = Math.round(evalPolynomial(polyY[0][0], polyY[1][0], polyY[2][0], polyY[3][0], 0.0F));
		int cou = 0;
		for (int k = 0; k < polyX[0].length; k++)
		{
			for (int j = 1; j <= pieces; j++)
			{
				float u = (float)j / (float)pieces;
				xpoints[cou] = Math.round(evalPolynomial(polyX[0][k], polyX[1][k], polyX[2][k], polyX[3][k], u));
				ypoints[cou] = Math.round(evalPolynomial(polyY[0][k], polyY[1][k], polyY[2][k], polyY[3][k], u));
				cou++;
			}

		}

		if (l.fillStyle != null)
		{
			xpoints[cou + 1] = bottomCorners[0][0];
			ypoints[cou + 1] = bottomCorners[1][0];
			xpoints[cou] = bottomCorners[0][1];
			ypoints[cou] = bottomCorners[1][1];
			l.fillStyle.drawPolygon(g, xpoints, ypoints, cou + 2);
		}
		xpoints[0] = linePointsSC[0][0];
		ypoints[0] = linePointsSC[1][0];
		l.style.drawOpenPolygon(g, xpoints, ypoints, cou);
	}

	protected void plotCurve(ChartGraphics g, int linePointsSC[][], LineDataSerie l)
	{
		if (linePointsSC.length > 1)
		{
			if (l.lineType == 1)
				plotCubicNatural(g, linePointsSC, l);
			if (l.lineType == 2)
				plotBSPLines(g, linePointsSC, l);
			if (l.lineType == 3)
				plotLeastSquares(g, linePointsSC, l);
		}
	}

	private float[][] naturalCubic(int n, int x[])
	{
		float g[] = new float[n + 1];
		float d[] = new float[n + 1];
		float D[] = new float[n + 1];
		g[0] = 0.5F;
		for (int i = 1; i < n; i++)
			g[i] = 1.0F / (4F - g[i - 1]);

		g[n] = 1.0F / (2.0F - g[n - 1]);
		d[0] = (float)(3 * (x[1] - x[0])) * g[0];
		for (int i = 1; i < n; i++)
			d[i] = ((float)(3 * (x[i + 1] - x[i - 1])) - d[i - 1]) * g[i];

		d[n] = ((float)(3 * (x[n] - x[n - 1])) - d[n - 1]) * g[n];
		D[n] = d[n];
		for (int i = n - 1; i >= 0; i--)
			D[i] = d[i] - g[i] * D[i + 1];

		float P[][] = new float[4][n];
		for (int i = 0; i < n; i++)
		{
			P[0][i] = x[i];
			P[1][i] = D[i];
			P[2][i] = (float)(3 * (x[i + 1] - x[i])) - 2.0F * D[i] - D[i + 1];
			P[3][i] = (float)(2 * (x[i] - x[i + 1])) + D[i] + D[i + 1];
		}

		return P;
	}

	private float evalPolynomial(float a1, float a2, float a3, float a4, float x)
	{
		return ((a4 * x + a3) * x + a2) * x + a1;
	}
}
